import { Injectable, Optional, Inject } from '@angular/core';
import { LoggerService } from './logger.service';
import { STORE_VERSION } from '../keys';

export type defaultTable = 'defult' | 'core' | 'system' | 'share';
@Injectable({
  providedIn: 'root'
})
export class IndexDbService {

  db: IDBDatabase;
  connect: IDBOpenDBRequest;
  connectIsSuccess = false;
  onupgradeneeded = false;
  constructor(private loggerService: LoggerService, @Optional() @Inject(STORE_VERSION) private storeVersion) {
    this.storeVersion = this.storeVersion === null ? 1 : this.storeVersion;
  }

  /**
   * 数据库初始化
   * @param version number
   * @param store_List string[]
   */
  initDB(store_List?: string[]) {
    return new Promise((resolve, reject) => {
      const connect = window.indexedDB.open('oms4', this.storeVersion);

      connect.onerror = (e) => {
        this.connectIsSuccess = false;
        this.loggerService.error(new Error('Database connection failed'), 'IndexDbService');
        reject(e);
      };

      connect.onsuccess = (e) => {
        this.connectIsSuccess = true;
        // tslint:disable-next-line:no-console
        console.log('Database connection succeeded');
        this.db = e.target['result'];
        resolve(e);
      };

      connect.onupgradeneeded = (e) => {
        // tslint:disable-next-line:no-console
        console.log('onupgradeneeded');
        this.onupgradeneeded = true;
        this.db = e.target['result'];
        const list = store_List ? ['defult', 'core', 'system', 'share', ...store_List] : ['defult', 'core', 'system', 'share'];
        this.creatStore(list);
      };
    });

  }

  /**
   * 添加数据
   * @param key string
   * @param store_name string
   * @param data any 值为 undefined 时执行删除逻辑
   */
  setData(key: string, store_name: defaultTable, data?: any) {
    if (this.connectIsSuccess) {
      if (data === undefined) {
        return this.remove(store_name, key);
      } else {
        return this.saveOrUpdate(store_name, key, data);
      }
    } else {
      return this.initDB().then(() => {
        if (data === undefined) {
          return this.remove(store_name, key);
        } else {
          return this.saveOrUpdate(store_name, key, data);
        }
      });
    }
  }
  /**
   * 查询数据
   * @param key string
   * @param store_name string
   */
  getData(key: string, store_name: defaultTable) {
    if (this.connectIsSuccess) {
      if (key === undefined) {
        return this.selectAll(store_name);
      }
      return this.selectByKey(store_name, key);
    } else {
      return this.initDB().then(() => {
        if (key === undefined) {
          return this.selectAll(store_name);
        }
        return this.selectByKey(store_name, key);
      });
    }
  }

  /**
   * 清空对象仓库
   * @param store_name 值为 undefined 时，清空所有对象仓库
   */
  clearStore(store_name?: string) {
    if (this.connectIsSuccess) {
      if (store_name === undefined) {
        this.clearStoreAll();
      } else {
        this.clearStoreByName(store_name);
      }
    } else {
      this.initDB().then(() => {
        if (store_name === undefined) {
          this.clearStoreAll();
        } else {
          this.clearStoreByName(store_name);
        }
      });
    }
  }

  /**
   * 删除指定数据库
   * @param DBName string
   */
  private deleteDB(DBName: string) {
    return new Promise((resolve, reject) => {
      this.db.close();
      const delReq = window.indexedDB.deleteDatabase(DBName);
      delReq.onsuccess = (e) => {
        resolve(null);
      };
      delReq.onerror = (e) => {
        reject(e);
      };
      delReq.onblocked = (e) => {
        reject(e);
      };
    });
  }

  /**
   * 根据key查询数据
   * @param store_name string
   * @param key string
   */
  private selectByKey(store_name, key) {
    const store = this.getObjectStore(store_name, 'readonly');
    return new Promise((resolve, reject) => {
      store.get(key).onsuccess = (e) => {
        resolve(e.target['result'] || {});
      };
      store.get(key).onerror = (e) => {
        reject(e.target['error']);
      };
    });
  }

  /**
   * 查询整个对象仓库
   * @param store_name string
   */
  private selectAll(store_name) {
    const store = this.getObjectStore(store_name, 'readonly');
    return new Promise((resolve, reject) => {
      store.getAll().onsuccess = (e) => {
        resolve(e.target['result'] || []);
      };
      store.getAll().onerror = (e) => {
        reject(e.target['error']);
      };
    });
  }

  /**
   * 添加或修改数据
   * @param store_name string
   * @param key string
   * @param data any
   */
  private saveOrUpdate(store_name: string, key: string, data: any) {
    return new Promise((resolve, reject) => {
      const store = this.getObjectStore(store_name, 'readwrite');
      let req;
      try {
        req = store.put(data, key);
      } catch (e) {
        throw (e);
      }
      req.onsuccess = (e) => {
        resolve(null);
      };
      req.onerror = (e) => {
        reject(e);
      };
    });
  }

  /**
   * 根据key删除对象仓库中的数据
   * @param store_name string
   * @param key string
   */
  private remove(store_name: string, key: string) {
    return new Promise((resolve, reject) => {
      const store = this.getObjectStore(store_name, 'readwrite');
      const req = store.get(key);
      req.onsuccess = (e) => {
        const del_req = store.delete(key);
        del_req.onsuccess = (eve) => {
          resolve(null);
        };
        del_req.onerror = (error) => {
          reject(error);
        };
      };
      req.onerror = (e) => {
        reject(e);
      };
    });
  }

  /**
   * 清空所有对象仓库
   */
  private clearStoreAll() {
    const storeList = this.db.objectStoreNames || [];
    for (let i = 0; i < storeList.length; i++) {
      const element = storeList[i];
      this.clearStore(element);
    }
  }

  /**
   * 清空指定对象仓库
   * @param store_name string
   */
  private clearStoreByName(store_name: string) {
    const store = this.getObjectStore(store_name, 'readwrite');
    store.clear();
  }

  /**
   * 创建对象仓库
   */
  private creatStore(store_List) {
    if (this.onupgradeneeded) {
      this.deleteStore();
    }
    if (store_List && store_List.length > 0) {
      for (let i = 0; i < store_List.length; i++) {
        const element = store_List[i];
        this.db.createObjectStore(element, { autoIncrement: true });
      }
    }
  }

  /**
   * 删除对象仓库
   * @param store_name string | string[]
   */
  private deleteStore(store_name?: string | string[]) {
    if (store_name === undefined) {
      const storeList = this.db.objectStoreNames || [];
      for (let i = 0; i < storeList.length; i++) {
        const element = storeList[i];
        this.db.deleteObjectStore(element);
      }
    } else if (Array.isArray(store_name)) {
      for (let i = 0; i < store_name.length; i++) {
        const element = store_name[i];
        this.db.deleteObjectStore(element);
      }
    } else {
      this.db.deleteObjectStore(store_name);
    }
  }

  /**
   * 获取事务
   * @param store_name string
   * @param mode readonly | readwrite
   */
  private getObjectStore(store_name: string, mode: 'readonly' | 'readwrite') {
    return this.db.transaction(store_name, mode).objectStore(store_name);
  }
}
